﻿#region Copyright ©2008-2011, Technische Universitaet Muenchen
// ====================================================================================================
//
// Last Changed by       $Author: kalus $
// Last Changed Date     $LastChangedDate: 2009-06-18 17:18:03 +0200 (Thu, 18 Jun 2009) $
// Last Changed Revision $Rev: 213 $
//
// ====================================================================================================
#endregion

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Linq;
using System.Linq.Expressions;
using Tum.CollabXT.SPEM.Resources;

namespace Tum.CollabXT.SPEM
{
    public class SPEMProcessProvider : IProcessProvider
    {
        #region Private Members (data structure)
        private List<IActivity> _Activities;
        private List<ITask> _Tasks;
        private List<IArtifact> _Artifacts;
        private List<IRole> _Roles;
        private List<IDiscipline> _Disciplines;
        private List<IMilestone> _Milestones;
        private List<ITopic> _Topics;
        private List<IAssociation> _Associations = new List<IAssociation>();

        private string _Name = string.Empty;
        private string _Description = string.Empty;

        private Dictionary<string, object> _ExtendedData = new Dictionary<string,object>();

        /// <summary>
        /// Path of the SPEM.xml.
        /// </summary>
        public string SPEMFile
        {
            get { return _SPEMFile; }
            set { _SPEMFile = value; }
        }
        private string _SPEMFile = null;

        #endregion


        public static string GetProviderName()
        {
            return Language.ProviderInfo_Name;
        }

        public static string GetProviderDescription()
        {
            return Language.ProviderInfo_Description;
        }

        public static string GetProviderAuthor()
        {
            return "© 2011 FH Rosenheim and TU München";
        }


        public SPEMProcessProvider() { }

        #region IProcessProvider Member: Init
        public void Initialize(Log log)
        {
            log.AddEntry(Language.Loading_PluginInfo);
            log.AddEntry(Language.Loading_Copyright);
            log.AddSeparator();


            if (SPEMFile == null)
                throw new SPEMException(Language.Error_Inititalizing_NoSPEM);


           LoadSPEMFile(log);

            log.AddEntry(Language.Loading_CompletedSuccessfully);
        }


        /// <summary>
        /// Initializes all structures with the data given in the SPEM file.
        /// </summary>
        /// <param name="log">Log to be used.</param>
        private void LoadSPEMFile(Log log)
        {
            // Load the spem document
            log.AddEntry(Language.Loading_Initializing);
            XmlDocument modelDocument = new XmlDocument();
            modelDocument.Load(SPEMFile);

            // Add addtional namespaces
            XmlNamespaceManager nsManager = new XmlNamespaceManager(modelDocument.NameTable);
            nsManager.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
            nsManager.AddNamespace("uma", "http://www.eclipse.org/epf/uma/1.0.5");

            log.AddEntry(Language.Loading_Tasks);
            LoadTasks(modelDocument, log, nsManager);

            log.AddEntry(Language.Loading_Activities);
            LoadActivities(modelDocument, log, nsManager);

            log.AddEntry(Language.Loading_Products);
            LoadProducts(modelDocument, log, nsManager);

            log.AddEntry(Language.Loading_Roles);
            LoadRoles(modelDocument, log, nsManager);

            log.AddEntry(Language.Loading_Disciplines);
            LoadDisciplines(modelDocument, log, nsManager);

            log.AddEntry(Language.Loading_Milestones);
            LoadMilestones(modelDocument, log, nsManager);

            log.AddEntry(Language.Loading_Dependencies);
            LoadDependencies(modelDocument, log, nsManager);

            _Topics = new List<ITopic>();
        }


        /// <summary>
        /// Loads all activities from a given SPEM document.
        /// </summary>
        /// <param name="modelDocument">SPEM document.</param>
        /// <param name="log">Log to be used.</param>
        /// <param name="nsManager">NamespaceManager</param>
        private void LoadActivities(XmlDocument modelDocument, Log log, XmlNamespaceManager nsManager)
        {
            _Activities = new List<IActivity>();
            XmlNodeList activityList = modelDocument.SelectNodes(Queries.MDL_GetActivities, nsManager);
            foreach (XmlNode activityNode in activityList)
            {
                IActivity activity = new Activity(activityNode);
                _Activities.Add(activity);

                XmlNodeList taskDescriptorList = activityNode.SelectNodes(Queries.MDL_GetTaskDesriptors, nsManager);
                foreach (XmlNode taskDescriptorNode in taskDescriptorList)
                {
                    ITask task = AssociationTools.GetTaskByID(this, taskDescriptorNode.SelectSingleNode("Task").InnerText);
                    _Associations.Add(new TaskToActivity(task, activity));
                }
            }
        }


        /// <summary>
        /// Loads all tasks from a given SPEM document.
        /// </summary>
        /// <param name="modelDocument">SPEM document.</param>
        /// <param name="log">Log to be used.</param>
        /// <param name="nsManager">NamespaceManager</param>
        private void LoadTasks(XmlDocument modelDocument, Log log, XmlNamespaceManager nsManager)
        {
            _Tasks = new List<ITask>();
            XmlNodeList taskList = modelDocument.SelectNodes(Queries.MDL_GetTasks, nsManager);
            foreach (XmlNode taskNode in taskList)
            {
                ITask task = new Task(taskNode);

                //Add list of output artifacts to extended data
                task.ExtendedData.Add("SPEM_outputs", new List<string>());
                foreach (XmlNode curOutput in taskNode.SelectNodes("Output", nsManager))
                    ((List<string>)task.ExtendedData["SPEM_outputs"]).Add(curOutput.InnerText);

                _Tasks.Add(task);
            }
        }

        /// <summary>
        /// Loads all products from a given SPEM document.
        /// </summary>
        /// <param name="modelDocument">SPEM document.</param>
        /// <param name="log">Log to be used.</param>
        /// <param name="nsManager">NamespaceManager</param>
        private void LoadProducts(XmlDocument modelDocument, Log log, XmlNamespaceManager nsManager)
        {
            _Artifacts = new List<IArtifact>();
            XmlNodeList productList = modelDocument.SelectNodes(Queries.MDL_GetProducts, nsManager);
            foreach (XmlNode productNode in productList)
            {
                var artifact = new Artifact(productNode);
                _Artifacts.Add(artifact);

                //Add associations to the artifact's creating activities
                var creatingTasks = _Tasks.Where(t => ((List<string>)t.ExtendedData["SPEM_outputs"]).Any(a => a.Equals(artifact.Id, StringComparison.InvariantCultureIgnoreCase)));
                foreach (var curCreatingTask in creatingTasks)
                {
                    //Get activity
                    var curTaskActivityAssocs = AssociationTools.GetAssociationsWithSource<ITask, IActivity>(this, curCreatingTask);
                    if (curTaskActivityAssocs.Length == 0)
                        continue;
                    var curTaskActivity = ((TaskToActivity)curTaskActivityAssocs[0]).Destination;

                    //Check if association exists already and if not create it
                    if (AssociationTools.GetAssociations<IActivity, IArtifact>(this, curTaskActivity, artifact).Length == 0)
                    {
                        _Associations.Add(new ActivityToArtifact(curTaskActivity, artifact));
                    }
                }
            }
        }

        /// <summary>
        /// Loads all roles from a given SPEM document.
        /// </summary>
        /// <param name="modelDocument">SPEM document.</param>
        /// <param name="log">Log to be used.</param>
        /// <param name="nsManager">NamespaceManager</param>
        private void LoadRoles(XmlDocument modelDocument, Log log, XmlNamespaceManager nsManager)
        {
            _Roles = new List<IRole>();
            XmlNodeList roleList = modelDocument.SelectNodes(Queries.MDL_GetRoles, nsManager);
            foreach (XmlNode roleNode in roleList)
            {
                IRole role = new Role(roleNode);

                // Load RoleResponsibleForProductDependency
                XmlNodeList responsibleForList = roleNode.SelectNodes("ResponsibleFor", nsManager);
                foreach (XmlNode responsibleForNode in responsibleForList)
                {
                    IArtifact artif = AssociationTools.GetArtifactByID(this, responsibleForNode.InnerText);
                    if (null != artif)
                        _Associations.Add(new RoleIsResponsibleForArtifact(role, artif));
                }

                _Roles.Add(role);
            }
        }

        /// <summary>
        /// Loads all disciplines from a given SPEM document.
        /// </summary>
        /// <param name="modelDocument">SPEM document.</param>
        /// <param name="log">Log to be used.</param>
        /// <param name="nsManager">NamespaceManager</param>
        private void LoadDisciplines(XmlDocument modelDocument, Log log, XmlNamespaceManager nsManager)
        {
            _Disciplines = new List<IDiscipline>();

            // Load Disciplines
            //XmlNodeList disciplineList = modelDocument.SelectNodes(Queries.MDL_GetDisciplines, nsManager);
            //foreach (XmlNode disciplineNode in disciplineList)
            //{
            //    IDiscipline discipline = new Discipline(disciplineNode);
            //    _Disciplines.Add(discipline);
            //    LoadWorkProducts(discipline, disciplineNode, log, nsManager);
            //}

            ////Load Domains
            XmlNodeList domainList = modelDocument.SelectNodes(Queries.MDL_GetDomains, nsManager);
            foreach (XmlNode domainNode in domainList)
            {
                IDiscipline domain = new Domain(domainNode);
                _Disciplines.Add(domain);
                LoadWorkProducts(domain, domainNode, log, nsManager);
            }

            //// Load WorkProductTypes
            //XmlNodeList workProductTypeList = modelDocument.SelectNodes(Queries.MDL_GetWorkProductTypes, nsManager);
            //foreach (XmlNode workProductTypeNode in workProductTypeList)
            //{
            //    IDiscipline workProductType = new WorkProductType(workProductTypeNode);
            //    _Disciplines.Add(workProductType);
            //    LoadWorkProducts(workProductType, workProductTypeNode, log, nsManager);
            //}

            //// Custom Categories
            //XmlNodeList customCategoryList = modelDocument.SelectNodes(Queries.MDL_GetCustomCategories, nsManager);
            //foreach (XmlNode customCategoryNode in customCategoryList)
            //{
            //    IDiscipline customCategory = new CustomCategory(customCategoryNode);
            //    _Disciplines.Add(customCategory);
            //    LoadWorkProducts(customCategory, customCategoryNode, log, nsManager);
            //}
        }

        /// <summary>
        /// Loads all milestones from a given SPEM document.
        /// </summary>
        /// <param name="modelDocument">SPEM document.</param>
        /// <param name="log">Log to be used.</param>
        /// <param name="nsManager">NamespaceManager</param>
        private void LoadMilestones(XmlDocument modelDocument, Log log, XmlNamespaceManager nsManager)
        {
            _Milestones = new List<IMilestone>();
            XmlNodeList milestoneList = modelDocument.SelectNodes(Queries.MDL_GetMilestones, nsManager);
            foreach (XmlNode milestoneNode in milestoneList)
            {
                _Milestones.Add(new Milestone(milestoneNode));
            }
        }


        /// <summary>
        /// Loads all workproducts from a given DisciplineNode.
        /// </summary>
        /// <param name="modelDocument">DisciplineNode.</param>
        /// <param name="modelDocument">DisciplineNode.</param>
        /// <param name="log">Log to be used.</param>
        /// <param name="nsManager">NamespaceManager</param>
        private void LoadWorkProducts(IDiscipline discipline, XmlNode disciplineNode, Log log, XmlNamespaceManager nsManager)
        {
            XmlNodeList workProductList = disciplineNode.SelectNodes(Queries.MDL_GetWorkProducts, nsManager);
            foreach (XmlNode workProductNode in workProductList)
            {
                IArtifact artifact = AssociationTools.GetArtifactByID(this, workProductNode.InnerText);
                if (null != artifact)
                    _Associations.Add(new ArtifactToDiscipline(artifact, discipline));
            }
        }

        /// <summary>
        /// Loads all depencies from a given SPEM document.
        /// </summary>
        /// <param name="modelDocument">SPEM document.</param>
        /// <param name="log">Log to be used.</param>
        /// <param name="nsManager">NamespaceManager</param>
        private void LoadDependencies(XmlDocument modelDocument, Log log, XmlNamespaceManager nsManager)
        {
            #region Product - Milestone
            {
                foreach (Milestone milestone in _Milestones)
                {
                    XmlNodeList requiredResults = modelDocument.SelectNodes(Queries.MDL_GetRequiredResult.Replace("CUSTOM_ID", milestone.Id));
                    foreach (XmlNode requiredResult in requiredResults)
                    {
                        XmlNodeList workProductNodes = modelDocument.SelectNodes(Queries.MDL_GetWorkProductDependency.Replace("CUSTOM_ID", requiredResult.InnerText));
                        foreach (XmlNode productNode in workProductNodes)
                        {
                            var artifact = AssociationTools.GetArtifactByID(this, productNode.InnerText);
                            if(artifact != null)
                                _Associations.Add(new ArtifactToMilestone(artifact, milestone));
                        }
                    }
                }
            }
            #endregion

            #region Product - Activity (
            //XmlNodeList phaseNodes = modelDocument.SelectNodes(Queries.MDL_GetPhases, nsManager);
            //foreach (XmlNode phaseNode in phaseNodes)
            //{
            //    String activityId = phaseNode.Attributes.GetNamedItem("id").Value;
            //    XmlNodeList outputInPhaseNodes = phaseNode.SelectNodes("BreakdownElement[@xsi:type='uma:TaskDescriptor']/Output", nsManager);
            //    XmlNodeList mandatoryInputInPhaseNodes = phaseNode.SelectNodes("BreakdownElement[@xsi:type='uma:TaskDescriptor']/MandatoryInput", nsManager);
            //    if (outputInPhaseNodes.Count > 0 || mandatoryInputInPhaseNodes.Count > 0)
            //    {
            //        var activity = AssociationTools.GetActivityByID(this, activityId);
            //        if (activity != null)
            //        {
            //            Action<XmlNodeList> addArtifactAssociations = delegate(XmlNodeList artifactNodes)
            //            {
            //                foreach (XmlNode curArt in artifactNodes)
            //                {
            //                    var art = AssociationTools.GetArtifactByID(this, curArt.InnerText);
            //                    if(art != null)
            //                        _Associations.Add(new ActivityToArtifact(activity, art));
            //                }
            //            };

            //            addArtifactAssociations(outputInPhaseNodes);
            //            addArtifactAssociations(mandatoryInputInPhaseNodes);
            //        }
            //    }
            //}
            #endregion

            #region Role - Product (Participating in)
            {
                XmlNodeList taskNodes = modelDocument.SelectNodes(Queries.MDL_GetTasks, nsManager);
                foreach (XmlNode taskNode in taskNodes)
                {
                    XmlNodeList performedByNodes = taskNode.SelectNodes("PerformedBy", nsManager);
                    if (performedByNodes.Count > 0)
                    {
                        XmlNodeList outputNodes = taskNode.SelectNodes("Output", nsManager);
                        XmlNodeList mandatoryInputNodes = taskNode.SelectNodes("MandatoryInput", nsManager);
                        if (outputNodes.Count > 0 || mandatoryInputNodes.Count > 0)
                        {
                            foreach (XmlNode performedByNode in performedByNodes)
                            {
                                var role = AssociationTools.GetRoleByID(this, performedByNode.InnerText);
                                if (role != null)
                                {
                                    Action<XmlNodeList> addParticipatedArtifacts = delegate(XmlNodeList artifactsList)
                                    {
                                        foreach (XmlNode curArt in artifactsList)
                                        {
                                            var art = AssociationTools.GetArtifactByID(this, curArt.InnerText);
                                            _Associations.Add(new RoleIsParticipatingInArtifact(role, art));
                                        }
                                    };

                                    addParticipatedArtifacts(outputNodes);
                                    addParticipatedArtifacts(mandatoryInputNodes);
                                }
                            }
                        }
                    }
                }
            }
            #endregion

            #region Role - Product (Responsible for)
            // This dependencies were already recognized
            #endregion

            #region Role - Activity

            #endregion

            #region Task - Role
            /*foreach(IRole role in _Roles) 
                {
                    XmlNodeList tasks = modelDocument.SelectNodes(Queries.MDL_GetTasksForRole, nsManager);
                    foreach (XmlNode task in tasks)
                    {
                        XmlAttributeCollection attributes = task.ParentNode.Attributes;
                        XmlNode id = attributes.GetNamedItem("id");
                        _Dependencies.Add(new RoleTaskDependency(id.Value, role.Id);
                    }
                }*/
            #endregion

            #region Role - Milestone

            #endregion

        }

        #endregion

        #region IProcessProvider Members
        public List<IActivity> Activities
        {
            get
            {
                return (_Activities);
            }
        }

        public List<ITask> Tasks
        {
            get
            {
                return (_Tasks);
            }
        }

        public List<IArtifact> Artifacts
        {
            get
            {
                return (_Artifacts);
            }
        }

        public List<IRole> Roles
        {
            get 
            {
                return (_Roles); 
            }
        }

        public List<ITopic> Topics
        {
            get
            {
                return (_Topics);
            }
        }

        public List<IDiscipline> Disciplines
        {
            get 
            {
                return (_Disciplines); 
            }
        }

        public List<IMilestone> Milestones
        {
            get 
            {
               return (_Milestones); 
            }
        }

        public List<IAssociation> Associations
        {
            get
            {
                return _Associations;
            }
        }

        public string Name
        {
            get
            {
                return _Name;
            }
        }

        public string Description
        {
            get
            {
                return _Description;
            }
        }

        public Dictionary<string, object> ExtendedData
        {
            get { return _ExtendedData; }
        }

        public string GetConfigPageName()
        {
            return "SPEMConfigPage.xaml";
        }

        public void Serialize(XmlNode outputParentNode)
        {
            XmlDocument xmlDoc = outputParentNode.OwnerDocument;

            XmlNode settingsNode = xmlDoc.CreateElement("settings");
            outputParentNode.AppendChild(settingsNode);

            XmlAttribute modelFileAttribute = xmlDoc.CreateAttribute("modelFile");
            modelFileAttribute.Value = SPEMFile;
            settingsNode.Attributes.Append(modelFileAttribute);
        }

        public void Deserialize(XmlNode inputParentNode)
        {
            XmlNode settingsNode = inputParentNode.SelectSingleNode("settings");

            try
            {
                _SPEMFile = null;
                _SPEMFile = settingsNode.Attributes["modelFile"].Value;
                if (!File.Exists(_SPEMFile))
                    _SPEMFile = null;
            }
            catch { }
        }

        #endregion
    }
}